﻿using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Linq;
using System.Windows.Browser;
using Caliburn.Micro;
using MediaOwl.Common;
using MediaOwl.Common.Messages;
using MediaOwl.Common.ScreenManagement;
using MediaOwl.WebSearch.Data.Translation;
using MediaOwl.WebSearch.Resources;
using Translation = MediaOwl.WebSearch.Data.Translation.Translation;

namespace MediaOwl.WebSearch.ViewModels
{
    [Export(typeof(IWorkitem<WebSearchViewModel>))]
    public sealed class BingTranslationViewModel : Workitem<WebSearchViewModel>
    {
        #region Fields

        private readonly IEventAggregator eventAggregator;
        private string currentPrimaryTranslation;

        #endregion

        #region Constructor
        [ImportingConstructor]
        public BingTranslationViewModel(IEventAggregator eventAggregator)
        {
            this.eventAggregator = eventAggregator;
            DisplayName = Captions.BingTranslationTitle;
            IsHomeScreen = true;
            Order = 4;

            SelectedSourceLanguage = "en";
            SelectedTargetLanguage = "de";
            Translation = string.Empty;
        }
        #endregion

        #region Properties with Backing-Fields

        private string textToTranslate;
        public string TextToTranslate
        {
            get { return textToTranslate; }
            set
            {
                textToTranslate = value;
                NotifyOfPropertyChange(() => TextToTranslate);
                NotifyOfPropertyChange(() => CanTranslateText);
            }
        }

        private string translation;
        public string Translation
        {
            get { return translation; }
            set
            {
                translation = value;
                NotifyOfPropertyChange(() => Translation);
            }
        }

        private IDictionary<string, string> availableLanguages;
        public IDictionary<string, string> AvailableLanguages
        {
            get { return availableLanguages; }
            set { availableLanguages = value; NotifyOfPropertyChange(() => AvailableLanguages);}
        }

        private BindableCollection<string> speakLanguages;
        public BindableCollection<string> SpeakLanguages
        {
            get { return speakLanguages; }
            set
            {
                speakLanguages = value;
                NotifyOfPropertyChange(() => SpeakLanguages);
                NotifyOfPropertyChange(() => CanSpeak);
            }
        }

        public bool CanSpeak
        {
            get {
                return SpeakLanguages != null && !string.IsNullOrEmpty(SelectedTargetLanguage) &&
                       (!string.IsNullOrEmpty(currentPrimaryTranslation) &&
                        SpeakLanguages.Contains(SelectedTargetLanguage));
            }
        }

        private string selectedSourceLanguage;
        public string SelectedSourceLanguage
        {
            get { return selectedSourceLanguage; }
            set
            {
                selectedSourceLanguage = value;
                NotifyOfPropertyChange(() => SelectedSourceLanguage);
                NotifyOfPropertyChange(() => CanTranslateText);
            }
        }

        private string selectedTargetLanguage;
        public string SelectedTargetLanguage
        {
            get { return selectedTargetLanguage; }
            set
            {
                selectedTargetLanguage = value;
                NotifyOfPropertyChange(() => SelectedTargetLanguage);
                NotifyOfPropertyChange(() => CanTranslateText);
                NotifyOfPropertyChange(() => CanSpeak);
            }
        }

        public bool CanTranslateText
        {
            get {
                if (string.IsNullOrEmpty(TextToTranslate) || string.IsNullOrEmpty(SelectedSourceLanguage) ||
                    string.IsNullOrEmpty(SelectedTargetLanguage) || SelectedSourceLanguage == SelectedTargetLanguage)
                    return false;

                return true;
            }
        }

        #endregion
            
        #region Methods

        public IEnumerable<IResult> GetAvailableLanguages()
        {
            yield return Show.Busy(this);

            yield return new GetAvailableLanguages((langAvail, speakLang) =>
                                                       {
                                                           AvailableLanguages = null;
                                                           AvailableLanguages = new Dictionary<string, string>(langAvail);

                                                           SpeakLanguages = null;
                                                           SpeakLanguages = new BindableCollection<string>(speakLang);
                                                       }, x => eventAggregator.Publish(new ErrorMessage(x)));

            yield return Show.NotBusy(this);
        }

        public IEnumerator<IResult> TranslateText()
        {
            return Translate();
        }

        public IEnumerator<IResult> TranslateShortCut()
        {
            return IsActive && CanTranslateText ? Translate() : null;
        }

        private IEnumerator<IResult> Translate()
        {
            yield return Show.Busy(this);

            yield return new Translation(TextToTranslate, SelectedSourceLanguage, SelectedTargetLanguage, (primaryTrans, response) =>
                                                                                                              {
                                                                                                                  currentPrimaryTranslation = primaryTrans;
                                                                                                                  Translation = "\n\n" + Translation;

                                                                                                                  if (response !=null)
                                                                                                                  {
                                                                                                                      Translation = "\n" + Translation;

                                                                                                                      string alt = response.Translations.Where(x => x.Rating > 0).Aggregate(string.Empty, 
                                                                                                                          (current, translationMatch) =>
                                                                                                                              current + string.Format("{0} ({1} %, Rating: {2})\n", 
                                                                                                                              translationMatch.TranslatedText, 
                                                                                                                              translationMatch.MatchDegree, 
                                                                                                                              translationMatch.Rating));

                                                                                                                      Translation = "\n\n" +string.Format(Captions.TranslationResultTextExtended, alt) + Translation;
                                                                                                                  }

                                                                                                                  Translation = string.Format(Captions.TranslationResultTextBase,
                                                                                                                         TextToTranslate,
                                                                                                                         AvailableLanguages[SelectedTargetLanguage],
                                                                                                                         primaryTrans) + Translation;
                                                                                                              }, x => eventAggregator.Publish(new ErrorMessage(x)));
            NotifyOfPropertyChange(() => CanSpeak);
            yield return Show.NotBusy(this);
        }

        public IEnumerable<IResult> Speak()
        {
            yield return Show.Busy(this);
            yield return new Speak(currentPrimaryTranslation,
                                   SelectedTargetLanguage,
                                   x => HtmlPage.Window.Navigate(new Uri(x, UriKind.Absolute), "_blank"),
                                   x => eventAggregator.Publish(new ErrorMessage(x)));   
            yield return Show.NotBusy(this);
        }

        #endregion
    }
}